package org.formal.system.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.session.Session;
import org.formal.common.service.BaseServiceImpl;
import org.formal.common.utils.DateUtils;
import org.formal.system.dao.ResourceDao;
import org.formal.system.dao.RoleResourceDao;
import org.formal.system.entity.ResourceEntity;
import org.formal.system.entity.RoleResourceEntity;
import org.formal.system.service.ResourceService;
import org.formal.system.shiro.manager.TokenManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

/**
 * 资源服务类
 * @author jiangyan
 *
 */
@Service
public class ResourceServiceImpl extends BaseServiceImpl<ResourceEntity> implements ResourceService{
	
	@Resource
	private ResourceDao resourceDao;
	
	@Resource
	private RoleResourceDao roleResourceDao;
	
	
	/**
	 * userId 用户id 
	 * roleId 用户正在使用的角色Id
	 * resources 获取从子级到父级排序的数据
	 * resourceMap 构建父子级Map
	 * resources 循环  存放父级id 并将子级合并
	 * 获取当前用户的所有权限
	 */
	@Override
	public List<ResourceEntity> loadUserResources() {
		Map<String,Object> map = new HashMap<String,Object>(2);
		Session session = TokenManager.getSession();
		map.put("userId",session.getAttribute("userId"));
		map.put("roleId",session.getAttribute("roleId"));
		List<ResourceEntity> resources = resourceDao.loadUserResources(map);
		List<ResourceEntity> resourceTrees = buildTree(resources);
		return resourceTrees;
	}


	/**
	 * 获得所有权限
	 */
	@Override
	public List<ResourceEntity> getResourceTreeAll() {
		List<ResourceEntity> resources = this.resourceDao.selectAll();
		List<ResourceEntity>  resourceTrees = buildTree(resources);
		return resourceTrees;
	}
	
	/**
	 * 根据传入的集合构建父子级关系
	 * 当父级为空时默认为最顶级，如果没有在map中找到 默认加入 key 为父级id value 为Resource
	 * 根据父级id找到resource 将所有子级放在一起 直到当前id 等于父级id 将子级加入到当前节点的子级中并移除
	 * 
	 * @param resources
	 * @return
	 */
	public List<ResourceEntity> buildTree(List<ResourceEntity> resources){
		Map<String,List<ResourceEntity>> resoureMap = new LinkedHashMap<String,List<ResourceEntity>>();
		List<ResourceEntity> resourceList = new ArrayList<ResourceEntity>();
		for(ResourceEntity resource : resources){
			if(resoureMap.containsKey(resource.getId())) {
				List<ResourceEntity> children = resoureMap.get(resource.getId());
				resource.getChildren().addAll(children);
				if(StringUtils.isBlank(resource.getParentId()) || "#".equals(resource.getParentId())) {
					resourceList.add(resource);
				}else {
					List<ResourceEntity> list = resoureMap.get(resource.getParentId());
					list.add(resource);
					resoureMap.put(resource.getParentId(), list);
				}
			}else {
				List<ResourceEntity> list = new ArrayList<ResourceEntity>();
				if(resoureMap.containsKey(resource.getParentId())) {
					list = resoureMap.get(resource.getParentId());
				}
				list.add(resource);
				resoureMap.put(resource.getParentId(), list);
			}
		}
		return resourceList;
	}

	/**
	 * 递归所有子节点
	 */
	@Override
	public void recurviseChildren(List<ResourceEntity> children, Integer level,String menuNo) {
		if(children != null && !children.isEmpty()) {
			int index = 0;
			for(ResourceEntity resourceEntity: children) {
				String number = String.format("%03d", index);
				String numberNo = menuNo + number;
				Integer lastLevel = level + 1;
				resourceEntity.setLevel(lastLevel);
				resourceEntity.setMenuNo(numberNo);
				this.resourceDao.updateByPrimaryKey(resourceEntity);
				List<ResourceEntity> child = getChilldrenByParentId(resourceEntity.getId());
				recurviseChildren(child,lastLevel,numberNo);
				index++;
			}
		}
		
	}
	
	/**
	 * 根据id获取所有子节点数据（不包含子节点下的子节点）
	 */
	@Override
	public List<ResourceEntity> getChilldrenByParentId(String id){
		Map<String, Object> map = new HashMap<String,Object>();
		map.put("parentId", id);
		List<ResourceEntity> children = this.selectByExample(map);
		return children;
	}

	/**
	 * 递归删除子节点
	 */
	@Override
	public void deleteByparentId(String id) {
		Example example = new Example(ResourceEntity.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("parentId", id);
		List<ResourceEntity> children = getChilldrenByParentId(id);
		for(ResourceEntity resource: children) {
			if(!resource.getIsLeaf()){
				deleteByparentId(resource.getId());
			}
		}
		this.resourceDao.deleteByExample(example);
	}

	/**
	 * 获取父节点下子节点数量
	 */
	@Override
	public int getCountByparentId(String parentId) {
		ResourceEntity resource = new ResourceEntity();
		resource.setParentId(parentId);
		return this.resourceDao.selectCount(resource);
	}

	/**
	 * 保存资源及修改关联状态 
	 * 父级如果不存在出本节点之外的节点 状态修改修改为叶子节点
	 * 本节点下所有子节点需要递归修改层级
	 * 现在父节点之前是否不存在节点 状态修改为 不是叶子节点
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveWithUpdateStatus(ResourceEntity entity) {
		String id = entity.getId();
		if(StringUtils.isNoneBlank(id)) {
			ResourceEntity oldEntity = this.selectByKey(id);
			String oldParentId = oldEntity.getParentId();
			String parentId = entity.getParentId();
			if (!oldParentId.equals(parentId)) {
				if(StringUtils.isNotEmpty(oldParentId)) {
					int oldCount = this.getCountByparentId(oldParentId);
					if (oldCount == 1) {
						ResourceEntity oldParent = this.selectByKey(oldParentId);
						oldParent.setIsLeaf(true);
						this.save(oldParent);
					}
				}
				List<ResourceEntity> reousrces = this.getChilldrenByParentId(entity.getId());
				if (!reousrces.isEmpty()) {
					//获取现在父节点层级 递归修改当前子节点及节点下的子节点
					this.recurviseChildren(reousrces,entity.getLevel(),entity.getMenuNo());
					entity.setIsLeaf(false);
				} else {
					entity.setIsLeaf(true);
				}
				setResourceEntity(entity);
			}
		}else {
			entity.setIsLeaf(true);
			setResourceEntity(entity);
		}
		this.save(entity);
	}	

	private void setResourceEntity(ResourceEntity entity) {
		ResourceEntity parent = this.selectByKey(entity.getParentId());
		String menuNo = "";
		if (parent != null) {
			if (parent.getIsLeaf()) {
				parent.setIsLeaf(false);
				this.save(parent);
			}
			entity.setLevel(parent.getLevel() + 1);
			menuNo += parent.getMenuNo();
		}else {
			entity.setLevel(0);
		}
		int count = this.getCountByparentId(entity.getParentId()) * 100;
		menuNo += String.format("%03d", count);
		entity.setMenuNo(menuNo);
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteWithChildrenById(String id) {
		ResourceEntity resource = this.selectByKey(id);
		super.delete(id);
		List<ResourceEntity> children = this.getChilldrenByParentId(resource.getParentId());
		if(children.size() == 0) {
			ResourceEntity parent = this.selectByKey(resource.getParentId());
			parent.setIsLeaf(true);
			this.updateNotNull(parent);
		}else if(!resource.getIsLeaf()) {
			this.deleteByparentId(id);
		}
	}

	@Override
	public List<ResourceEntity> getListByRoleId(String roleId){
		List<ResourceEntity> resourceList = new ArrayList<ResourceEntity>();
		Example example = new Example(RoleResourceEntity.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("roleId", roleId);
		List<RoleResourceEntity> roleResourceList = this.roleResourceDao.selectByExample(example);
		for(RoleResourceEntity roleResourceEntity : roleResourceList) {
			ResourceEntity resourceEntity = this.resourceDao.selectByPrimaryKey(roleResourceEntity.getResourceId());
			if (resourceEntity != null) {
				resourceList.add(resourceEntity);
			}
		}
		return resourceList;
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveRoleResource(String id, String[] resourceArray) {
		Example example = new Example(RoleResourceEntity.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("roleId",id);
		criteria.andNotIn("resourceId", Arrays.asList(resourceArray));
		this.roleResourceDao.deleteByExample(example);
		for(String resourceId : resourceArray) {
			RoleResourceEntity entity = new RoleResourceEntity();
			entity.setRoleId(id);
			entity.setResourceId(resourceId);
			RoleResourceEntity roleResourceEntity = this.roleResourceDao.selectOne(entity);
			if(roleResourceEntity == null) {
				entity.setCreateTime(DateUtils.getCurDateTime());
				entity.setCreateUser(TokenManager.getUserId());
				this.roleResourceDao.insertSelective(entity);
			}
		}
	}


	@Override
	public List<ResourceEntity> getExcludeResources(String resourceId) {
		Example example = new Example(ResourceEntity.class);
		Criteria criteria = example.createCriteria();
		criteria.andEqualTo("isDelete", "0");
		if(StringUtils.isNoneBlank(resourceId)) {
			criteria.andNotEqualTo("id", resourceId);
			criteria.andNotEqualTo("parentId", resourceId);
		}
		List<ResourceEntity> resources = this.selectByExample(example);
		return resources;
	}
}
